#include <stdio.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <complex.h>
#include <fftw3.h>

#define pi 2*acos(0)
#define fmode FFTW_ESTIMATE

typedef struct vector {
  fftw_complex *rho, *chi;
  double alpha;
} vect;

typedef struct work {
  int n;
  double	alpha;

  fftw_complex *rho;
  fftw_complex *chi;

  fftw_complex *Phi;
  fftw_complex *Z;
  fftw_complex *Z_u;
  fftw_complex *P_u;

} work, *work_ptr;

typedef struct control {
  double H;  // energy
  double M;  // mean level
  double P;  // momentum
} ctrl, *ctrl_ptr;

typedef struct params {
  int n, k_cut, num_iter; 
  int k_min, k_max;
  double force_A;
  int ref_lvl, skip;
  int stokes, decay_p;  
  double g, cfl, c, tmax, t_skip, dt;
  char runname[80];
  char resname[80];
  ctrl current; 
  work_ptr w_ptr;

} params, *params_ptr;

//  --  ffts.c
extern void err_msg(char* str);
extern void init(int *argc, char **argv, params_ptr in, work_ptr wrk) ;
extern void hilbert(fftw_complex *in, fftw_complex *out);
extern void project(fftw_complex *in, fftw_complex *out);
extern void pproject(fftw_complex *in, fftw_complex *out);
extern void ffilter(params_ptr in);
extern void reconstruct_surface(work_ptr in);
extern void reconstruct_potential(work_ptr in); 
extern void update_dfunc(work_ptr in);
extern void fft(fftw_complex *in, fftw_complex *out);
extern void ifft(fftw_complex *in, fftw_complex *out);
extern void der(fftw_complex *in, fftw_complex *out);
extern void rhs(work_ptr in, int m);
extern void rk4(params_ptr in);
extern void fforcing(params_ptr in);

extern void generate_derivatives(work_ptr in, int m);

extern void prep_control_params(params_ptr in);
extern void hamiltonian(params_ptr in);
extern void mean_level(params_ptr in);
extern void momentum(params_ptr in);


extern void r_transform(fftw_complex *in, fftw_complex *out, double alpha);
extern void projector(fftw_complex *in, fftw_complex *out, double alpha);
extern void iprojector(fftw_complex *in, fftw_complex *out, double alpha);
extern fftw_complex theta(fftw_complex r, fftw_complex w, fftw_complex d);

//  --  prep.c



extern void init_prep(params_ptr in);
extern void write_out(fftw_complex* in, char* str);
extern void write_out_surface(work_ptr in, char* str);

extern void read_data(params_ptr in);



extern void stokes_wave(double tol, params_ptr in);


